package com.thinkingcoder.tcrpc.core.config;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;

import com.thinkingcoder.tcrpc.core.api.RpcContext;
import com.thinkingcoder.tcrpc.core.balancer.LoadBalancer;
import com.thinkingcoder.tcrpc.core.balancer.RoundRobinLoadBalancer;
import com.thinkingcoder.tcrpc.core.consumer.ConsumerBootstrap;
import com.thinkingcoder.tcrpc.core.filter.ContextParameterFilter;
import com.thinkingcoder.tcrpc.core.filter.Filter;
import com.thinkingcoder.tcrpc.core.listener.ApolloChangedListener;
import com.thinkingcoder.tcrpc.core.meta.InstanceMeta;
import com.thinkingcoder.tcrpc.core.registry.RegistryCenter;
import com.thinkingcoder.tcrpc.core.registry.tc.TcRegistryCenter;
import com.thinkingcoder.tcrpc.core.router.GrayRouter;
import com.thinkingcoder.tcrpc.core.router.Router;

import lombok.extern.slf4j.Slf4j;

/**
 * config for consumer.
 */
@Slf4j
@Configuration
@Import({AppProperties.class, ConsumerProperties.class})
public class ConsumerConfig {

    @Autowired
    private AppProperties appProperties;

    @Autowired
    private ConsumerProperties consumerProperties;

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "apollo.bootstrap", value = "enabled")
    ApolloChangedListener consumerApolloChangedListener() {
        return new ApolloChangedListener();
    }

    @Bean
    ConsumerBootstrap createConsumerBootstrap() {
        return new ConsumerBootstrap();
    }

    @Bean
    @Order(Integer.MIN_VALUE + 1)
    public ApplicationRunner consumerBootstrapRunner(@Autowired ConsumerBootstrap consumerBootstrap) {
        return x -> {
            log.info("consumerBootstrap starting ...");
            consumerBootstrap.start();
            log.info("consumerBootstrap started ...");
        };
    }

    @Bean
    public LoadBalancer<InstanceMeta> loadBalancer() {
        return new RoundRobinLoadBalancer<>();
    }

    @Bean
    public Router<InstanceMeta> router() {
        return new GrayRouter(consumerProperties.getGrayRatio());
    }

    @Bean(initMethod = "start", destroyMethod = "stop")
    @ConditionalOnMissingBean
    public RegistryCenter consumerRegistry() {
        return new TcRegistryCenter();
    }

    @Bean
    public Filter defaultFilter() {
        return new ContextParameterFilter();
    }

    @Bean
    @RefreshScope
    public RpcContext createContext(@Autowired Router router, @Autowired LoadBalancer loadBalancer,
        @Autowired List<Filter> filters) {
        RpcContext context = new RpcContext();
        context.setRouter(router);
        context.setLoadBalancer(loadBalancer);
        context.setFilters(filters);
        context.getParameters().put("app.id", appProperties.getId());
        context.getParameters().put("app.namespace", appProperties.getNamespace());
        context.getParameters().put("app.env", appProperties.getEnv());
        context.setConsumerProperties(consumerProperties);
        return context;
    }
}
